package com.xuecheng.content.service.jobhandler;

import com.xuecheng.base.exception.XueChengPlusException;
import com.xuecheng.content.feignclient.CourseIndex;
import com.xuecheng.content.feignclient.SearchServiceClient;
import com.xuecheng.content.mapper.CoursePublishMapper;
import com.xuecheng.content.model.po.CoursePublish;
import com.xuecheng.content.service.CoursePublishService;
import com.xuecheng.messagesdk.model.po.MqMessage;
import com.xuecheng.messagesdk.service.MessageProcessAbstract;
import com.xuecheng.messagesdk.service.MqMessageService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName CoursePublishTask
 * @Description 课程发布任务类
 * @Date 2023/6/25 15:25
 * @Version 1.0
 */
@Slf4j
@Component
public class CoursePublishTask extends MessageProcessAbstract {

    @Autowired
    CoursePublishService coursePublishService;

    @Autowired
    SearchServiceClient searchServiceClient;

    @Autowired
    CoursePublishMapper coursePublishMapper;

    //任务调度入口
    @XxlJob("CoursePublishJobHandler")
    public void coursePublishJobHandler() throws Exception {
        //分片参数
        int shardIndex = XxlJobHelper.getShardIndex();      //执行器序号
        int shardTotal = XxlJobHelper.getShardTotal();      //执行器总数
        log.debug("shardIndex = " + shardIndex + "，shardTotal=" + shardTotal);
        //调用抽象类的方法执行任务
        //参数: 分片序号、分片总数、消息类型、一次最多取到的任务数量、一次任务调度执行的超时时间
        process(shardIndex, shardTotal, "course_publish", 30, 60);
    }

    //执行课程发布任务的逻辑，如果此方法地出异常说明任务执行失败
    @Override
    public boolean execute(MqMessage mqMessage) {

        //从 mqMessage 拿到课程 id
        Long courseId = Long.parseLong(mqMessage.getBusinessKey1());

        //课程静态化上传到 minio
        generateCourseHtml(mqMessage, courseId);

        //向 elasticsearch 写索引数据
        saveCourseIndex(mqMessage, courseId);

        //向 redis 写缓存
        saveCourseCache(mqMessage, courseId);

        //返回 true 表示任务完成
        return true;
    }

    //第一个任务：生成课程静态化页面并上传至文件系统
    public void generateCourseHtml(MqMessage mqMessage, long courseId) {
        log.debug("开始进行课程静态化,课程 id: {}", courseId);
        //消息 id
        Long id = mqMessage.getId();
        //消息处理的 service
        MqMessageService mqMessageService = this.getMqMessageService();
        //消息幂等性处理
        int stageOne = mqMessageService.getStageOne(id);
        if (stageOne > 0) {
            log.debug("课程静态化已处理直接返回，课程 id: {}", courseId);
            return;
        }
        //开始进行课程静态化生成 html 页面
        File file = coursePublishService.generateCourseHtml(courseId);
        if (file == null) {
            XueChengPlusException.cast("生成的静态页面为空！");
        }
        //将 html 上传到 minio
        coursePublishService.uploadCourseHtml(courseId, file);
        //保存第一阶段状态
        mqMessageService.completedStageOne(id);
    }

    //第二个任务：保存课程索引信息
    public void saveCourseIndex(MqMessage mqMessage, long courseId) {
        //任务id
        Long taskId = mqMessage.getId();
        MqMessageService mqMessageService = this.getMqMessageService();
        //取出第二个阶段状态
        int stageTwo = mqMessageService.getStageTwo(taskId);

        //任务幂等性处理
        if (stageTwo > 0) {
            log.debug("课程索引信息已写入，无需执行...");
            return;
        }
        //查询课程信息，调用搜索服务添加索引接口

        //从课程发布表查询课程信息
        CoursePublish coursePublish = coursePublishMapper.selectById(courseId);
        CourseIndex courseIndex = new CourseIndex();
        BeanUtils.copyProperties(coursePublish, courseIndex);

        //远程调用
        Boolean res = searchServiceClient.add(courseIndex);
        if (!res) {
            XueChengPlusException.cast("添加索引失败");
        }

        //完成本阶段的任务
        mqMessageService.completedStageTwo(taskId);
    }

    //第三个任务：将课程信息缓存至 redis
    public void saveCourseCache(MqMessage mqMessage, long courseId) {
        log.debug("将课程信息缓存至 redis，课程 id: {}", courseId);
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

}






